package com.aspire.wap.core.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;

/**
 * http client 单例实现 包括线程池
 * 
 * <ul>
 * <li>
 * 2009-10-11 huyunan 增加控制返回结果行数的方法</li>
 * <li>
 * 2009-09-27 huyunan 读取response时使用stream进行获取,增加服务器超时设置</li>
 * </ul>
 * 
 * @see MAX_CONNECTIONS_PERHOST
 * @see MAX_TOTAL_CONNECTIONS
 * @see TIME_OUT
 * 
 * @author huyunan 2009-9-3 上午10:06:15
 * 
 * @version 1.0
 */
public class HttpClientTool {

	/** 每host最大连接数 默认15 */
	public static final String MAX_CONNECTIONS_PERHOST = "max-connections-perhost";
	/** 总链接数 默认3000 */
	public static final String MAX_TOTAL_CONNECTIONS = "max-total-connections";
	/** 超时时间 默认1000 */
	public static final String TIME_OUT = "time-out";

	public static final int DEFAULT_MAX_CONNECTIONS_PERHOST = 15;
	public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 3000;
	public static final int DEFAULT_TIME_OUT = 1000;

	private final Logger logger = Logger.getLogger(HttpClientTool.class);

	private HttpClient httpClient = null;
	private MultiThreadedHttpConnectionManager connectionManager = null;
	private HttpConnectionManagerParams connectionManagerParams = null;

	private HttpClientTool() {
		ResourceBundle resource = null;
		int maxConnectionsPerHost = DEFAULT_MAX_CONNECTIONS_PERHOST;
		int maxTotalConnections = DEFAULT_MAX_TOTAL_CONNECTIONS;
		int timeout = DEFAULT_TIME_OUT;
		try {
			resource = ResourceBundle.getBundle("httpclient-configure",
					new Locale("", ""));
			maxConnectionsPerHost = NumberUtils.toInt(resource
					.getString(MAX_CONNECTIONS_PERHOST),
					DEFAULT_MAX_CONNECTIONS_PERHOST);
			maxTotalConnections = NumberUtils.toInt(resource
					.getString(MAX_TOTAL_CONNECTIONS),
					DEFAULT_MAX_TOTAL_CONNECTIONS);
			timeout = NumberUtils.toInt(resource.getString(TIME_OUT), 1000);
		}
		catch (Exception ex) {
			logger.error("读取配置文件", ex);
		}
		connectionManagerParams = new HttpConnectionManagerParams();
		// 针对每个host发出的最大连接数
		connectionManagerParams
				.setDefaultMaxConnectionsPerHost(maxConnectionsPerHost);
		// 发出的最大连接数
		connectionManagerParams.setMaxTotalConnections(maxTotalConnections);
		// 连接超时限制
		connectionManagerParams.setConnectionTimeout(timeout);
		// 服务器超时设置，服务器在timout设定时间内还未得到accept方法返回的套接字实例
		connectionManagerParams.setSoTimeout(timeout);
		connectionManager = new MultiThreadedHttpConnectionManager();
		connectionManager.setParams(connectionManagerParams);
		httpClient = new HttpClient(connectionManager);
	}

	public static HttpClientTool getInstant() {
		return SingletonHolder.INSTANCE;
	}

	// Initialization on demand holder idiom
	static class SingletonHolder {
		static HttpClientTool INSTANCE = new HttpClientTool();
	}

	/**
	 * 发送http请求
	 * 
	 * @param method
	 * @return
	 * @author huyunan 2009-10-11 上午08:12:16
	 */
	public String sendMethod(HttpMethod method) {
		return sendMethod(method, 0);
	}

	/**
	 * 发送http请求
	 * 
	 * @param method
	 * @param resultNum
	 * @return
	 * @author huyunan 2009-10-11 上午08:12:28
	 */
	public String sendMethod(HttpMethod method, int resultNum) {
		String response = "";
		String requestUrl = "";
		try {
			requestUrl = method.getURI().getEscapedURI();
			// 获取返回状态
			int status = httpClient.executeMethod(method);
			if (HttpStatus.SC_OK == status) {
				// 状态成功
				// 从服务端获取反馈
				response = getResponseBody(method.getResponseBodyAsStream(),
						"", resultNum);
			}
			else {
				response = String.valueOf(status);
			}
		}
		catch (Exception ex) {
			logger.error("发送http method url：" + requestUrl, ex);
		}
		finally {
			method.releaseConnection();
		}
		return response;
	}

	/**
	 * 获取页面内容
	 * 
	 * @param request
	 * @param methodType
	 * @param url
	 * @param charset
	 * @return
	 * @author huyunan 2009-9-27 上午09:49:11
	 */
	public String getPageContent(HttpServletRequest request, String methodType,
			String url, String charset) {
		return getPageContent(request, methodType, url, charset, 0);
	}

	public String getPageContent(HttpServletRequest request, String methodType,
			String url, String charset, int resultNum) {
		String content = "";
		try {
			// 判断请求类型
			HttpMethod method = null;
			if (StringUtils.isNotBlank(methodType) && methodType.equals("GET")) {
				method = new GetMethod(url);
			}
			else {
				method = new PostMethod(url);
			}
			if (StringUtils.isNotBlank(charset)) {
				method.getParams().setContentCharset(charset);
			}
			if (request != null) {
				// 添加header
				Enumeration<String> headerNames = request.getHeaderNames();
				String headerName = "";
				while (headerNames.hasMoreElements()) {
					headerName = headerNames.nextElement();
					if (headerName.equalsIgnoreCase("content-length")) {
						method.addRequestHeader(headerName, "0");
					}
					else {
						method.addRequestHeader(headerName, request
								.getHeader(headerName));
					}
				}
				// end 添加header
			}
			// 发送请求
			int status = httpClient.executeMethod(method);
			if (HttpStatus.SC_OK == status) {
				// 状态成功
				// 从服务端获取反馈
				content = getResponseBody(method.getResponseBodyAsStream(), "",
						resultNum);
			}
		}
		catch (Exception ex) {
			logger.error("发送http method url：" + url, ex);
		}
		return content;
	}

	/**
	 * 从流中读取数据
	 * 
	 * @param is
	 * @param charset
	 * @param resultNum
	 * @return
	 * @author huyunan 2009-10-11 上午08:10:04
	 */
	public String getResponseBody(InputStream is, String charset, int resultNum) {
		StringBuilder body = new StringBuilder();
		try {
			BufferedReader reader = null;
			if (StringUtils.isBlank(charset)) {
				charset = "UTF-8";
			}
			reader = new BufferedReader(new InputStreamReader(is, charset));
			String line = null;
			line = reader.readLine();
			int index = 0;
			while (line != null) {
				body.append(line);
				line = reader.readLine();
				index++;
				// 判断是否到了读取行数的限制
				if (resultNum > 0 && index == resultNum) {
					// 达到限制跳出
					break;
				}
			}
		}
		catch (Exception ex) {
			logger.error("获取服务端response", ex);
		}
		finally {
			try {
				is.close();
			}
			catch (IOException ex) {
				logger.error("获取服务端response", ex);
			}
		}
		return body.toString();
	}

	/**
	 * 提交post请求
	 * 
	 * @param request
	 * @param url
	 * @return
	 * @author huyunan 2010-5-13 上午08:35:15
	 */
	public Map<String, String> sendPost(HttpServletRequest request, String url) {
		Map<String, String> result = new HashMap<String, String>();
		try {
			PostMethod method = new PostMethod(url);
            method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8");
			if (request != null) {
				// 重新构造拼接参数
				Enumeration<String> paraEnum = request.getParameterNames();
				NameValuePair nameValuePair = null;
				String para = "";
				while (paraEnum.hasMoreElements()) {
					para = paraEnum.nextElement();
					//modi by x_minmin rurl参数不传过去 2010-05-19
					if (StringUtils.isNotBlank(para) && !para.equalsIgnoreCase("rurl")) {
						// 构造参数
						nameValuePair = new NameValuePair(para, request
								.getParameter(para));
						method.addParameter(nameValuePair);
					}
				}
				// 重新构造header
				Enumeration<String> headerNames = request.getHeaderNames();
				String headerName = "";
				while (headerNames.hasMoreElements()) {
					headerName = headerNames.nextElement();
					method.addRequestHeader(headerName, request
							.getHeader(headerName));
				}
				// 重新构造cookie
				Cookie[] cookies = request.getCookies();
				String setCooke = "";
				if (cookies != null) {
					for (int a = 0; a < cookies.length; a++) {
						Cookie cookie = cookies[a];
						setCooke += cookie.getName() + "=" + cookie.getValue()
								+ ";";
					}
					method.setRequestHeader("Cookie", setCooke);
				}
			}
			// 发送请求
			int status = httpClient.executeMethod(method);
            
            //判断状态为302时
            if (status == HttpStatus.SC_MOVED_PERMANENTLY || 
                    status == HttpStatus.SC_MOVED_TEMPORARILY) {
                        // 从头中取出转向的地址
                        Header locationHeader = method.getResponseHeader("location");
                        String location = null;
                        if (locationHeader != null) {
                         location = locationHeader.getValue();
                         //System.out.println("需要再次跳转的地址:" + location);
                         
                         method = new PostMethod(location);
                         //发送请求
                         status = httpClient.executeMethod(method);

                        } else {
                         //System.err.println("Location field value is null.");
                        }
                        
                    }
            
			if (HttpStatus.SC_OK == status) {
				// 状态成功
				// 从服务端获取反馈
				String content = getResponseBody(method
						.getResponseBodyAsStream(),
						method.getResponseCharSet(), 0);
				// 解析返回头
				String contentType = "";
				Header contentTypeHeader = method
						.getResponseHeader("Content-Type");
				if (contentTypeHeader != null) {
					contentType = contentTypeHeader.getValue();
				}
				String charset = method.getResponseCharSet();
				result.put("Content-Type", contentType);
				result.put("charset", charset);
				String ctype = StringUtils
						.substringBeforeLast(contentType, ";");
				result.put("ctype", ctype);
				result.put("content", content);
			}
			else {
				logger.warn("发送http method [url=" + url + "][status=" + status
						+ "]");
			}
		}
		catch (Exception ex) {
			logger.error("发送http method url：" + url, ex);
		}
		return result;
        
        
	}

}